package org.springframework.boot.context.properties.bind;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.SimpleTypeConverter;
import org.springframework.beans.propertyeditors.FileEditor;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.util.Assert;

import java.beans.PropertyEditor;
import java.util.*;
import java.util.function.Consumer;

final class BindConverter {

    private static final Set<Class<?>> EXCLUDED_EDITORS;

    static {
        Set<Class<?>> excluded = new HashSet<>();
        excluded.add(FileEditor.class);
        EXCLUDED_EDITORS = Collections.unmodifiableSet(excluded);
    }

    private static BindConverter sharedInstance;

    private final ConversionService conversionService;

    private BindConverter(ConversionService conversionService,
                          Consumer<PropertyEditorRegistry> propertyEditorInitializer) {
        Assert.notNull(conversionService, "ConversionService must not be null");
    }

    private List<ConversionService> getConversionServices(ConversionService conversionService,
                                                          Consumer<PropertyEditorRegistry> propertyEditorInitializer) {

    }

    private static class TypeConverterConversionService extends GenericConversionService {

    }

    private static class TypeConverterConverter implements ConditionalGenericConverter {

        private final SimpleTypeConverter typeConverter;

        TypeConverterConverter(SimpleTypeConverter typeConverter) {
            this.typeConverter = typeConverter;
        }

        @Override
        public Set<ConvertiblePair> getConvertibleTypes() {
            return Collections.singleton(new ConvertiblePair(String.class,Object.class));
        }

        @Override
        public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
            return getPropertyEditor(targetType.getType()) != null;
        }

        @Override
        public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
            SimpleTypeConverter typeConverter = this.typeConverter;
            return typeConverter.convertIfNecessary(source,targetType.getType());
        }

        private PropertyEditor getPropertyEditor(Class<?> type) {
            if (type == null || type == Object.class || Collection.class.isAssignableFrom(type)
                    || Map.class.isAssignableFrom(type)) {
                return null;
            }
            SimpleTypeConverter typeConverter = this.typeConverter;
            PropertyEditor editor = typeConverter.getDefaultEditor(type);
            if (editor == null) {
                editor = typeConverter.findCustomEditor(type,null);
            }
            if (editor == null && String.class != type) {
                editor = BeanUtils.findEditorByConvention(type);
            }
            if (editor == null || EXCLUDED_EDITORS.contains(editor.getClass())) {
                return null;
            }
            return editor;
        }
    }
}
